package yycore
import chisel3._
import chisel3.util._
import common.Constants._
import common.Instructions._

object RV32I_Instr {
  val table = Array(
    AUIPC -> List(Y, BRType.none, OP1_IMU,  OP2_PC, OEN_0, OEN_0, FuType.alu, ALUOpType.ADD,   WB_EXE, REN_1),
    LUI   -> List(Y, BRType.none, OP1_IMU,  OP2_X,  OEN_0, OEN_0, FuType.alu, ALUOpType.COPY1, WB_EXE, REN_1),


    LW    -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.lsu, LSUOpType.lw,    WB_EXE, REN_1),
    LH    -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.lsu, LSUOpType.lh,    WB_EXE, REN_1),
    LB    -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.lsu, LSUOpType.lb,    WB_EXE, REN_1),

    LHU   -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.lsu, LSUOpType.lhu,   WB_EXE, REN_1),
    LBU   -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.lsu, LSUOpType.lbu,   WB_EXE, REN_1),

    SW    -> List(Y, BRType.none, OP1_RS1, OP2_IMS, OEN_1, OEN_1, FuType.lsu, LSUOpType.sw,    WB_X,   REN_0),
    SH    -> List(Y, BRType.none, OP1_RS1, OP2_IMS, OEN_1, OEN_1, FuType.lsu, LSUOpType.sh,    WB_X,   REN_0),
    SB    -> List(Y, BRType.none, OP1_RS1, OP2_IMS, OEN_1, OEN_1, FuType.lsu, LSUOpType.sb,    WB_X,   REN_0),

    ADDI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.ADD,   WB_EXE, REN_1),
    ANDI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.AND,   WB_EXE, REN_1),
    ORI   -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.OR,    WB_EXE, REN_1),
    XORI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.XOR,   WB_EXE, REN_1),
    SLTU  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_0, FuType.alu, ALUOpType.SLTU,  WB_EXE, REN_1),
    SLTI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.SLT,   WB_EXE, REN_1),
    SLTIU -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.SLTU,  WB_EXE, REN_1),
    SLLI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.SLL,   WB_EXE, REN_1),
    SRAI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.SRA,   WB_EXE, REN_1),
    SRLI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.SRL,   WB_EXE, REN_1),

    ADD   -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.ADD,   WB_EXE, REN_1),
    SUB   -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.SUB,   WB_EXE, REN_1),

    // logic
    AND   -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.AND,   WB_EXE, REN_1),
    OR    -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.OR,    WB_EXE, REN_1),
    XOR   -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.XOR,   WB_EXE, REN_1),
    SLT   -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.SLT,   WB_EXE, REN_1),
    SLL   -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.SLL,   WB_EXE, REN_1),
    SRA   -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.SRA,   WB_EXE, REN_1),
    SRL   -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.SRL,   WB_EXE, REN_1),

    JAL   -> List(Y, BRType.jal,  OP1_IMJ, OP2_PC,  OEN_0, OEN_0, FuType.alu, ALUOpType.ADD,   WB_PC4, REN_1),
    JALR  -> List(Y, BRType.jalr, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.ADD,   WB_PC4, REN_1),


    BEQ   -> List(Y, BRType.beq,   OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.alu, ALUOpType.ADD,  WB_X,   REN_0),
    BNE   -> List(Y, BRType.bne,   OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.alu, ALUOpType.ADD,  WB_X,   REN_0),
    BLT   -> List(Y, BRType.blt,   OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.alu, ALUOpType.ADD,  WB_X,   REN_0),
    BLTU  -> List(Y, BRType.bltu,  OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.alu, ALUOpType.ADD,  WB_X,   REN_0),
    BGE   -> List(Y, BRType.bge,   OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.alu, ALUOpType.ADD,  WB_X,   REN_0),
    BGEU  -> List(Y, BRType.bgeu,  OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.alu, ALUOpType.ADD,  WB_X,   REN_0)
  )
}

object RV64I_Instr {
  val table = Array(
    LD    -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.lsu, LSUOpType.ld,    WB_EXE, REN_1),
    LWU   -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.lsu, LSUOpType.lwu,   WB_EXE, REN_1),
    SD    -> List(Y, BRType.none, OP1_RS1, OP2_IMS, OEN_1, OEN_1, FuType.lsu, LSUOpType.sd,    WB_X,   REN_0),

    ADDW  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.ADDW,  WB_EXE, REN_1),
    SUBW  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.SUBW,  WB_EXE, REN_1),
    SLLW  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.SLLW,  WB_EXE, REN_1),
    SRLW  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.SRLW,  WB_EXE, REN_1),
    SRAW  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.alu, ALUOpType.SRAW,  WB_EXE, REN_1),

    ADDIW  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.ADDW,  WB_EXE, REN_1),
    SLLIW  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.SLLW,  WB_EXE, REN_1),
    SRLIW  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.SRLW,  WB_EXE, REN_1),
    SRAIW  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.alu, ALUOpType.SRAW,  WB_EXE, REN_1),
  )
}

object RVIInstr {
  val table = RV32I_Instr.table ++ RV64I_Instr.table
}
